home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
TECHNICA
/
COMPUTER
/
H254.ZIP
/
IRITSM3S.ZIP
/
IRIT
/
VIEWOBJ.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-25
|
22KB
|
654 lines
/*****************************************************************************
* "Irit" - the 3d polygonal solid modeller. *
* *
* Written by: Gershon Elber Unix - X11 Ver 0.1, Mar. 1990 *
******************************************************************************
* Module to handle viewing of objects in the ViewWindow. *
*****************************************************************************/
#include <stdio.h>
#include <math.h>
#include "program.h"
#include "attribut.h"
#include "graphgen.h"
#include "objects.h"
#include "freeform.h"
#include "geomat3d.h"
#include "primitiv.h"
#include "windows.h"
#include "viewobj.h"
#include "graphgen.h"
#define MAX_ROTATE_ANGLE 45.0 /* Maximum rates used by interact mode. */
#define MAX_TRANSLATE_FACTOR 2.0
#define MAX_SCALE_FACTOR 2.0
static int
ViewNormals = FALSE,
ClosedObject = FALSE,
SupportClosedObject = FALSE,
NormalsColor = 1, /* View normals to object. */
QuitView = FALSE;
static RealType
LastCoord[3], /* Used to store last point we moved/draw to. */
NormalsSize = 0.1;
static ObjectStruct
*ActiveObjList = NULL; /* Currently displayed objects. */
/* Prototypes for the View Object module: */
static void InteractHandleInput(ObjectStruct *PObjList,
MatrixType GlblViewMat, MatrixType GlblPrspMat);
static MatrixType *ComputeCrntViewMatrix(void);
static void ViewGeomObjectList(ObjectStruct *PObjList);
static int GetInternal(void);
static void ViewCagdPolyline(CagdPolylineStruct *Pl, int Color,
MatrixType Mat);
static void TestQuitView(void);
static void ViewPolygon(PolygonStruct *Pl, int Color, int IsPolyline,
MatrixType Mat, int ViewInternal);
static void DepthCueMoveTo(RealType Coord[3]);
static void DepthCueDrawTo(RealType NewCoord[3]);
#ifdef __GL__
static void DrawPolygonSolid(PolygonStruct *PPolygon, MatrixType Mat);
#endif /* __GL__ */
/*****************************************************************************
* Routine to interactively display geometric object(s) PObj on the View *
* window enable rotating/translating/scaling it using the Input Device. *
*****************************************************************************/
void InteractPolyObject(ObjectStruct *PObj, RealType *UpdateGlblMat)
{
ObjectStruct *ViewMat, *PrspMat;
MatrixType ViewMatCopy, PrspMatCopy; /* Save original trans. to recover. */
if (!GlblDoGraphics) return;
if ((ViewMat = GetObject("VIEW_MAT")) == NULL) {
WndwInputWindowPutStr(
"No view transformation matrix VIEW_MAT!");
return;
}
else if (!IS_MAT_OBJ(ViewMat)) {
WndwInputWindowPutStr(
"VIEW_MAT object was modified (not matrix object)");
return;
}
MAT_COPY(ViewMatCopy, ViewMat -> U.Mat);
if ((PrspMat = GetObject("PRSP_MAT")) == NULL) {
WndwInputWindowPutStr(
"No perspective transformation matrix PRSP_MAT!");
return;
}
else if (!IS_MAT_OBJ(PrspMat)) {
WndwInputWindowPutStr(
"PRSP_MAT object was modified (not matrix object)");
return;
}
MAT_COPY(PrspMatCopy, PrspMat -> U.Mat);
/* Get data from input device, interpret it, and display interactively: */
InteractHandleInput(PObj, ViewMat -> U.Mat, PrspMat -> U.Mat);
if (!APX_EQ(*UpdateGlblMat, 0.0)) {
MAT_COPY(ViewMat -> U.Mat, ViewMatCopy); /* Recover. */
MAT_COPY(PrspMat -> U.Mat, PrspMatCopy);
}
}
/*****************************************************************************
* Routine to handle data from the input device (keyboard, mouse etc.) - *
* clip it against the sub windows of the interactive menu and perform the *
* required transfomation, by updating the global view matrix object VIEW_MAT *
* The input data in the Rotation/Translation/Scaling sub windows is used *
* (horizontal distance from sub window center) to set amount of change. *
*****************************************************************************/
static void InteractHandleInput(ObjectStruct *PObjList,
MatrixType GlblViewMat, MatrixType GlblPrspMat)
{
int UpdateView;
RealType ChangeFactor;
MatrixType Mat, OrigViewMat, OrigPrspMat;
#if !defined(__MSDOS__) && !defined(DJGCC)
long WinID, DispID, ColorMapID;
#endif /* !__MSDOS__ && !DJGCC */
/* Save copy of original matrix, so we can recover if reset is required. */
GEN_COPY(OrigViewMat, GlblViewMat, sizeof(MatrixType));
GEN_COPY(OrigPrspMat, GlblPrspMat, sizeof(MatrixType));
ActiveObjList = PObjList;
QuitView = FALSE;
#ifdef __MSDOS__
IntrWndwPop(TransWindowID, TRUE, TRUE);
#endif /* __MSDOS__ */
#if defined(__MSDOS__) || defined(DJGCC)
GGClearViewArea();
/* Set the async. function for intr_lib to refresh the view window. */
IntrWndwSetRefreshFunc(ViewWindowID,
(IntrIntFunc) UpdateInteractHandleInput);
#endif /* __MSDOS__ || DJGCC */
UpdateInteractHandleInput(); /* Display it for the first time. */
while (TRUE) {
QuitView = FALSE;
UpdateView = TRUE;
switch (GGGetGraphicEvent(&ChangeFactor)) {
case EVENT_SCR_OBJ_TGL: /* Its Coordinate system - toggle it. */
UpdateView = FALSE;
break;
case EVENT_PERS_ORTHO_TGL: /* Its View mode - toggle it. */
MatGenUnitMat(Mat);
break;
case EVENT_PERS_ORTHO_Z: /* Its Perspective Z focal point modif. */
if (GlblViewMode != VIEW_PERSPECTIVE) {
GGTone(1000, 100); /* Do some noise! */
UpdateView = FALSE;
break;
}
/* Make it between 0.5 and 1.5: */
ChangeFactor = ChangeFactor / 2.0 + 1.0;
GlblPrspMat[2][2] *= ChangeFactor;
GlblPrspMat[2][3] *= ChangeFactor;
GlblPrspMat[3][2] *= ChangeFactor;
MatGenUnitMat(Mat);
break;
case EVENT_ROTATE_X: /* Its rotation along the X axis. */
MatGenMatRotX1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
break;
case EVENT_ROTATE_Y: /* Its rotation along the Y axis. */
MatGenMatRotY1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
break;
case EVENT_ROTATE_Z: /* Its rotation along the Z axis. */
MatGenMatRotZ1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
break;
case EVENT_TRANSLATE_X: /* Its translation along the X axis. */
MatGenMatTrans(ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0, 0.0,
Mat);
break;
case EVENT_TRANSLATE_Y: /* Its translation along the Y axis. */
MatGenMatTrans(0.0, ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0,
Mat);
break;
case EVENT_TRANSLATE_Z: /* Its translation along the Z axis. */
MatGenMatTrans(0.0, 0.0, ChangeFactor * MAX_TRANSLATE_FACTOR,
Mat);
break;
case EVENT_SCALE: /* Its scaling along all axes. */
if (ChangeFactor > 0.0) /* Make it around 1... */
ChangeFactor = ChangeFactor * MAX_SCALE_FACTOR + 1.0;
else
ChangeFactor = 1.0 /
(-ChangeFactor * MAX_SCALE_FACTOR + 1.0);
MatGenMatScale(ChangeFactor, ChangeFactor, ChangeFactor, Mat);
break;
case EVENT_DEPTH_CUE:
if (!GlblDepthCue) GGMySetLineStyle(SOLID_LINE);
MatGenUnitMat(Mat);
break;
#ifdef __GL__ /* Only on GL library systems. */
case EVENT_DRAW_SOLID:
MatGenUnitMat(Mat);
break;
#else
case EVENT_DRAW_SOLID:
#endif
case EVENT_SAVE_GIF:
case EVENT_SAVE_PS:
case EVENT_SAVE_MATRIX:
GGTone(800, 100);
GGTone(400, 200);
UpdateView = FALSE;
break;
case EVENT_RESET_MATRIX:
GEN_COPY(GlblViewMat, OrigViewMat, sizeof(MatrixType));
GEN_COPY(GlblPrspMat, OrigPrspMat, sizeof(MatrixType));
MatGenUnitMat(Mat);
break;
case EVENT_QUIT:
ActiveObjList = NULL;
#ifdef __MSDOS__
IntrWndwPop(StatusWindowID, TRUE, TRUE);
#endif /* __MSDOS__ */
return; /* Its Quit. */
default:
FatalError("InteractHandleInput: Undefine input type, exit\n");
}
if (UpdateView) {
switch (GlblTransformMode) {/* Udpate the global viewing matrix. */
case TRANS_SCREEN:
MatMultTwo4by4(GlblViewMat, GlblViewMat, Mat);
break;
case TRANS_OBJECT:
MatMultTwo4by4(GlblViewMat, Mat, GlblViewMat);
break;
}
#if defined(__MSDOS__) || defined(DJGCC)
GGClearViewArea();
#endif /* __MSDOS__ || DJGCC */
UpdateInteractHandleInput();
}
}
}
/*****************************************************************************
* Compute the current view using VIEW_MAT and PRSP_MAT matrices. *
*****************************************************************************/
static MatrixType *ComputeCrntViewMatrix(void)
{
static MatrixType CrntViewMat;
ObjectStruct *ViewMat, *PrspMat;
if ((ViewMat = GetObject("VIEW_MAT")) == NULL) {
WndwInputWindowPutStr(
"No view transformation matrix VIEW_MAT!");
return NULL;
}
else if (!IS_MAT_OBJ(ViewMat)) {
WndwInputWindowPutStr(
"VIEW_MAT object was modified (not matrix object)");
return NULL;
}
if ((PrspMat = GetObject("PRSP_MAT")) == NULL) {
WndwInputWindowPutStr(
"No perspective transformation matrix PRSP_MAT!");
return NULL;
}
else if (!IS_MAT_OBJ(PrspMat)) {
WndwInputWindowPutStr(
"PRSP_MAT object was modified (not matrix object)");
return NULL;
}
switch (GlblViewMode) {
case VIEW_ORTHOGRAPHIC:
GEN_COPY(CrntViewMat, ViewMat -> U.Mat, sizeof(MatrixType));
break;
case VIEW_PERSPECTIVE:
MatMultTwo4by4(CrntViewMat, ViewMat -> U.Mat, PrspMat -> U.Mat);
break;
}
return &CrntViewMat;
}
/*****************************************************************************
* Routine to update the viewing screen. On unix systems this routine may *
* be invoked when X sends expose event to this program (see xgrphgen.c). *
* In MSDOS this routine is static and been called from InteractHandleInput *
* above routine only. *
*****************************************************************************/
void UpdateInteractHandleInput(void)
{
#if !defined(__MSDOS__) && !defined(DJGCC)
GGClearViewArea();
#endif /* !__MSDOS__ && !DJGCC */
if (ActiveObjList != NULL)
ViewGeomObject(ActiveObjList); /* And display it... */
#if !defined(__MSDOS__) && !defined(DJGCC)
GGGraphicFlush();
#endif /* !__MSDOS__ && !DJGCC */
}
/*****************************************************************************
* Routine to display the geometric objects in PObjList, by simply calling *
* ViewGeomObject on all of them. PObjList must be of type OBJ_LIST_OBJ. *
*****************************************************************************/
static void ViewGeomObjectList(ObjectStruct *PObjList)
{
int Param = 0;
ObjectStruct *PObj;
while ((PObj = PObjList -> U.PObjList[Param]) != NULL &&
Param++ < MAX_OBJ_LIST && !QuitView) {
ViewGeomObject(PObj);
}
}
/*****************************************************************************
* Routine to fetch the internal parameter from the INTERNAL object. *
*****************************************************************************/
static int GetInternal(void)
{
int Internal;
ObjectStruct *PObj = GetObject("INTERNAL");
if (PObj == NULL || !IS_NUM_OBJ(PObj)) {
WndwInputWindowPutStr("No numeric object name INTERNAL is defined");
Internal = DEFAULT_INTERNAL;
}
else
Internal = !APX_EQ((PObj -> U.R), 0.0);
return Internal;
}
/*****************************************************************************
* Routine to display the geometric object PObj on the View Window: *
* Uses the global view transformation as computed by ComputeCrntViewMat. *
*****************************************************************************/
void ViewGeomObject(ObjectStruct *PObj)
{
int Color, IsPolyline,
DrawCtlPtColor = GetDrawCtlPt(),
ViewInternal = GetInternal(),
RealResolution = GetResolution(FALSE);
CagdPolylineStruct *CagdPl;
PolygonStruct *Pl;
MatrixType *CrntMat;
if (!GlblDoGraphics) return;
QuitView = FALSE;
if (IS_OLST_OBJ(PObj)) {
/* Invoke the display routine on each of its componenets. */
ViewGeomObjectList(PObj);
return;
}
if (!IS_GEOM_OBJ(PObj)) {
WndwInputWindowPutStr("None displayable object ignored.");
return;
}
Color = GetObjectColor(PObj);
if ((CrntMat = ComputeCrntViewMatrix()) == NULL)
return;
if (IS_POLY_OBJ(PObj)) {
Pl = PObj -> U.Pl.P;
IsPolyline = IS_POLYLINE_OBJ(PObj);
if (!IsPolyline && SupportClosedObject)
ClosedObject = TRUE;
while (Pl && !QuitView) {
ViewPolygon(Pl, Color, IsPolyline, *CrntMat, ViewInternal);
Pl = Pl -> Pnext;
TestQuitView();/* if break display in the middle - Set QuitView. */
}
ClosedObject = FALSE;
}
else if (IS_CRV_OBJ(PObj)) {
if (!GlblDrawSolid) {
ComputeCurveIsoLines(PObj);
if (RealResolution > 0)
ViewCagdPolyline(PObj -> U.Crv.PLPolys, Color, *CrntMat);
if (DrawCtlPtColor)
ViewCagdPolyline(PObj -> U.Crv.CtlPoly, DrawCtlPtColor,
*CrntMat);
}
}
else if (IS_SRF_OBJ(PObj)) {
if (GlblDrawSolid) {
ComputeSurfacePolygons(PObj);
SetObjectColor(PObj -> U.Srf.Polygons, GetObjectColor(PObj));
ViewGeomObject(PObj -> U.Srf.Polygons);
}
else {
ComputeSurfaceIsoLines(PObj);
if (RealResolution > 0) {
CagdPl = PObj -> U.Srf.PLPolys;
while (CagdPl && !QuitView) {
ViewCagdPolyline(CagdPl, Color, *CrntMat);
CagdPl = CagdPl -> Pnext;
TestQuitView();/* Break display in middle - Set QuitView. */
}
}
if (DrawCtlPtColor) {
CagdPl = PObj -> U.Srf.CtlMesh;
while (CagdPl && !QuitView) {
ViewCagdPolyline(CagdPl, DrawCtlPtColor, *CrntMat);
CagdPl = CagdPl -> Pnext;
TestQuitView();
}
}
}
}
}
/*****************************************************************************
* Routine to display one polyline on the view window using the matrix Mat *
* as a transformation matrix. *
*****************************************************************************/
static void ViewCagdPolyline(CagdPolylineStruct *Pl, int Color,
MatrixType Mat)
{
int i, j;
PointType P, TempP;
CagdPtStruct
*Points = Pl -> Polyline;
/* Since we can not guarantee that CagdRType == RealType: */
for (i = 0; i < 3; i++) TempP[i] = Points[0].Pt[i];
MatMultVecby4by4(P, TempP, Mat); /* Transform the first point. */
DepthCueMoveTo(P);
GGMySetColor(Color);
for (i = 1; i < Pl -> Length; i++) {
for (j = 0; j < 3; j++) TempP[j] = Points[i].Pt[j];
MatMultVecby4by4(P, TempP, Mat);
DepthCueDrawTo(P);
};
}
/*****************************************************************************
* Routine to test if quit display event - occured - *
* Right button was clicked on mouse. *
*****************************************************************************/
static void TestQuitView(void)
{
QuitView = GGIsAbortKeyPressed();
}
/*****************************************************************************
* Routine to display one polygon on the view window using the matrix Mat as *
* a transformation matrix. *
*****************************************************************************/
static void ViewPolygon(PolygonStruct *Pl, int Color, int IsPolyline,
MatrixType Mat, int ViewInternal)
{
int NumOfPoints, DontDraw,
ShowNormals = ViewNormals && !IsPolyline;
PointType P, CenterP;
VertexStruct *V, *VStart;
V = VStart = Pl -> V;
if (V == NULL) FatalError("ViewPolygon: Empty polygon to view\n");
GGMySetColor(Color);
#ifdef __GL__ /* Only on GL library systems. */
if (GlblDrawSolid && !IsPolyline) {
DrawPolygonSolid(Pl, Mat);
return;
}
#endif
MatMultVecby4by4(P, V -> Pt, Mat); /* Transform the first point. */
DepthCueMoveTo(P);
DontDraw = IS_INTERNAL_EDGE(V) && !ViewInternal; /* Draw next edge? */
if (ShowNormals) { /* If display of normal is required. */
NumOfPoints = 0;
PT_CLEAR(CenterP);
}
do {
V = V -> Pnext;
if (ShowNormals) {
NumOfPoints++;
PT_ADD(CenterP, CenterP, V -> Pt);
}
MatMultVecby4by4(P, V -> Pt, Mat);
/* If edge is INTERNAL (Irit.h) and not ViewInternal - dont draw: */
if (DontDraw)
DepthCueMoveTo(P);
else
DepthCueDrawTo(P);
DontDraw = IS_INTERNAL_EDGE(V) && !ViewInternal; /* Draw next edge? */
} while (V != VStart && V -> Pnext != NULL);
if (ShowNormals) {
PT_SCALE(CenterP, 1.0/NumOfPoints); /* Estimate for normals. */
MatMultVecby4by4(P, CenterP, Mat); /* Transform the first point. */
DepthCueMoveTo(P);
PT_COPY(P, Pl -> Plane);
PT_SCALE(P, NormalsSize);
PT_ADD(CenterP, CenterP, P);
MatMultVecby4by4(P, CenterP, Mat); /* Transform the second point. */
GGMySetColor(NormalsColor);
DepthCueDrawTo(P);
}
}
/*****************************************************************************
* Routine to set the normals default values: *
*****************************************************************************/
void ViewSetNormals(RealType *Active, RealType *Size, RealType *Color)
{
ViewNormals = !APX_EQ(*Active, 0.0);
NormalsSize = *Size;
NormalsColor = (int) *Color;
}
/*****************************************************************************
* Routine to set the closed objects default. *
*****************************************************************************/
void ViewSetClosed(RealType *Closed)
{
SupportClosedObject = !APX_EQ(*Closed, 0.0);
}
/*****************************************************************************
* Routine to mave to 3D point given as Coord[3], using Mat transform. *
*****************************************************************************/
static void DepthCueMoveTo(RealType Coord[3])
{
GEN_COPY(LastCoord, Coord, 3 * sizeof(RealType)); /* Set crnt point. */
}
/*****************************************************************************
* Routine to draw to 3D point given as Coord[3], using Mat transform, from *
* the last point we moved to. *
*****************************************************************************/
static void DepthCueDrawTo(RealType NewCoord[3])
{
RealType MiddleCoord[3], t;
if (ClosedObject && NewCoord[2] < LastCoord[2]) {
GEN_COPY(LastCoord, NewCoord, 3 * sizeof(RealType));
return;
}
/* Implementation of simple depth cue - if line is >Z or <Z ... */
if (LastCoord[2] <= 0.0 && NewCoord[2] <= 0.0) { /* Draw the <Z part: */
if (GlblDepthCue) GGMySetLineStyle(DOTTED_LINE);
GGMyMove(LastCoord[0], LastCoord[1]);
GGMyDraw(NewCoord[0], NewCoord[1]); /* DRAW! */
}
else if (LastCoord[2] >= 0.0 && NewCoord[2] >= 0.0 ||
ABS(LastCoord[2] - NewCoord[2]) < EPSILON) {
if (GlblDepthCue) GGMySetLineStyle(SOLID_LINE);
GGMyMove(LastCoord[0], LastCoord[1]);
GGMyDraw(NewCoord[0], NewCoord[1]); /* DRAW! */
}
else { /* Line intersect Z = 0 plane. */
t = LastCoord[2] / (LastCoord[2] - NewCoord[2]);
MiddleCoord[0] = LastCoord[0] * (1.0 - t) + NewCoord[0] * t;
MiddleCoord[1] = LastCoord[1] * (1.0 - t) + NewCoord[1] * t;
if (GlblDepthCue) GGMySetLineStyle(SOLID_LINE);
if (LastCoord[2] > 0.0) {
GGMyMove(LastCoord[0], LastCoord[1]);
GGMyDraw(MiddleCoord[0], MiddleCoord[1]); /* DRAW! */
}
else {
GGMyMove(MiddleCoord[0], MiddleCoord[1]);
GGMyDraw(NewCoord[0], NewCoord[1]); /* DRAW! */
}
if (GlblDepthCue) GGMySetLineStyle(DOTTED_LINE);/* Draw the <Z part: */
if (LastCoord[2] < 0.0) {
GGMyMove(LastCoord[0], LastCoord[1]);
GGMyDraw(MiddleCoord[0], MiddleCoord[1]); /* DRAW! */
}
else {
GGMyMove(MiddleCoord[0], MiddleCoord[1]);
GGMyDraw(NewCoord[0], NewCoord[1]); /* DRAW! */
}
}
GEN_COPY(LastCoord, NewCoord, 3 * sizeof(RealType)); /* Set crnt point. */
}
#ifdef __GL__
/****************************************************************************
* Routine to draw a polygon full. *
****************************************************************************/
static void DrawPolygonSolid(PolygonStruct *PPolygon, MatrixType Mat)
{
int i, l = 0;
float Normal[3], Length;
double MappedVertex[3];
RealType V1R[3], V2R[3], V3R[3];
VertexStruct *PList = PPolygon -> V;
GGMyDrawPolygonSolid(NULL, NULL, TRUE);
do {
MatMultVecby4by4(V1R, PList -> Pt, Mat);
for (i = 0; i < 3; i++) MappedVertex[i] = V1R[i];
/* Each vertex has different normal - specify them. */
MatMultVecby4by4(V1R, PList -> Pt, Mat);
for (i = 0; i < 3; i++)
V2R[i] = PList -> Pt[i] + PList -> Normal[i];
MatMultVecby4by4(V2R, V2R, Mat);
for (i = 0; i < 3; i++) Normal[i] = V2R[i] - V1R[i];
Length = sqrt(SQR(Normal[0]) + SQR(Normal[1]) + SQR(Normal[2]));
for (i = 0; i < 3; i++) Normal[i] /= -Length;
GGMyDrawPolygonSolid(MappedVertex, Normal, TRUE);
PList = PList -> Pnext;
if (l++ >= 255)
FatalError("GL: polygon too complex (> 256 vertices).\n");
}
while (PList != NULL && PList != PPolygon -> V);
GGMyDrawPolygonSolid(NULL, NULL, FALSE);
}
#endif /* __GL__ */